﻿
// MultiOpenDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "MultiOpen.h"
#include "MultiOpenDlg.h"
#include "afxdialogex.h"

#include <Tlhelp32.h>

#include "hook.h"
#pragma comment(lib, "MultiOpenDll.lib")


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMultiOpenDlg 对话框



CMultiOpenDlg::CMultiOpenDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MULTIOPEN_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDI_MYICON);

	m_pWndOk = NULL;
	m_pWndCancle = NULL;
	m_hHook = NULL;
	ZeroMemory(&m_Notify, sizeof(m_Notify));


}

void CMultiOpenDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_CHECK1, m_CBWeChat);
	DDX_Control(pDX, IDC_CHECK2, m_CBYoudaoNote);
	DDX_Control(pDX, PC_WECHAT, m_PCWeChat);
	DDX_Control(pDX, PC_YOUDAO, m_PCYouDao);
}

BEGIN_MESSAGE_MAP(CMultiOpenDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(BC_OK, &CMultiOpenDlg::OnBnClickedOk)
	ON_BN_CLICKED(BC_CANCLE, &CMultiOpenDlg::OnBnClickedCancle)
	ON_MESSAGE(WM_WECHAT, &CMultiOpenDlg::OnWeChatMessage)
	ON_MESSAGE(WM_YOUDAO, &CMultiOpenDlg::OnYoudaoMessage)
	ON_MESSAGE(WM_SHELL_NOTIFYICON, &CMultiOpenDlg::OnShell_NotifyIcon)
	ON_WM_CLOSE()
	ON_WM_DESTROY()
	ON_WM_CTLCOLOR()
END_MESSAGE_MAP()


//遍历进程，将指定进程的斥体关闭
void CMultiOpenDlg::GetProcessInfoCloseMutual(DWORD dwFlag)
{
    //拍进程快照
    HANDLE hSnapshot  = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    //获取快照失败，直接返回
    if (INVALID_HANDLE_VALUE == hSnapshot)
    {
        return;
    }

    PROCESSENTRY32 pe32 = { 0 };
    pe32.dwSize = sizeof(PROCESSENTRY32);

    //遍历进程
    if (Process32First(hSnapshot, &pe32))
    {
        do
        {
			if (dwFlag == WECHAT)
			{
				//比较进程名，如果匹配，则取出pid关闭句柄
                if (lstrcmp(pe32.szExeFile, TEXT("WeChat.exe")) == 0)
                {
					m_MutualClose.CloseMutualHandle(pe32.th32ProcessID, dwFlag);
                }
			}
			else
			{
                if (lstrcmp(pe32.szExeFile, TEXT("YoudaoNote.exe")) == 0)
                {
					m_MutualClose.CloseMutualHandle(pe32.th32ProcessID, dwFlag);
                }
			}
        } while (Process32Next(hSnapshot, &pe32));
    }

    //关闭句柄
    CloseHandle(hSnapshot);
}


// CMultiOpenDlg 消息处理程序
BOOL CMultiOpenDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	//获取确定按钮和取消按钮的窗口句柄
	m_pWndOk = GetDlgItem(BC_OK);
	m_pWndCancle = GetDlgItem(BC_CANCLE);
	if (!m_pWndOk || !m_pWndCancle)
	{
        MessageBox(TEXT("因为某些原因，程序无法正常运行"), TEXT("提示"), MB_OK);
		PostQuitMessage(0);
	}

	//先将取消按钮变灰
	m_pWndCancle->EnableWindow(FALSE);

	RECT rect;

	//将微信和有道云的图标跳到合适的大小
	m_PCWeChat.GetWindowRect(&rect);
	ScreenToClient(&rect);
	rect.right = rect.right - 10;
	rect.bottom = rect.bottom - 10;
	m_PCWeChat.MoveWindow(&rect);

    m_PCYouDao.GetWindowRect(&rect);
    ScreenToClient(&rect);
    rect.right = rect.right - 10;
    rect.bottom = rect.bottom - 10;
	m_PCYouDao.MoveWindow(&rect);

	//获取使用到的函数指针
	BOOL bRet = m_MutualClose.GetFunctionPtrInfo();
	if (!bRet)
	{
		MessageBox(TEXT("出了一些问题，可能未获取到 ntdll 中的某些函数，所以此程序无法正常运行"), TEXT("提示"), MB_OK);
		PostQuitMessage(0);
	}

	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CMultiOpenDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMultiOpenDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


//确定按钮
void CMultiOpenDlg::OnBnClickedOk()
{
	if (!m_CBWeChat.GetCheck() && !m_CBYoudaoNote.GetCheck())
	{
		return;
	}

	//如果是微信多开
	if (m_CBWeChat.GetCheck())
	{
		//遍历进程，找到所有微信，将其互斥体关闭
		GetProcessInfoCloseMutual(WECHAT);
	}
	//如果是有道云笔记多开
	if (m_CBYoudaoNote.GetCheck())
	{
		//遍历进程，找到所有有道云笔记，将其互斥体关闭
		GetProcessInfoCloseMutual(YOUDAONOTE);
	}

	if (m_hHook != NULL)
	{
        MessageBox(TEXT("自己检测到程序有bug，所以程序即将退出！"), TEXT("提示"), MB_OK);
		PostQuitMessage(0);
		return;
	}

	//设置全局钩子，监控进程的启动
	m_hHook = SetWindowsHookEx(
		WH_GETMESSAGE,
		GetMsgProc,
        ::GetModuleHandle(TEXT("MultiOpenDll")),
        0);

	if (m_hHook == NULL)
	{
        MessageBox(TEXT("出于某些原因，程序无法正常运行，即将退出！"), TEXT("提示"), MB_OK);
		PostQuitMessage(0);
		return;
	} 

	//将复选框的按钮以及确定按钮变灰
	m_CBWeChat.EnableWindow(FALSE);
	m_CBYoudaoNote.EnableWindow(FALSE);
	m_pWndOk->EnableWindow(FALSE);

	//将取消按钮变亮
	m_pWndCancle->EnableWindow(TRUE);
}


//取消按钮
void CMultiOpenDlg::OnBnClickedCancle()
{
	if (m_hHook == NULL)
	{
		return;
	}

	BOOL bRet = UnhookWindowsHookEx(m_hHook);
	if(!bRet)
	{
		MessageBox(TEXT("出于某些原因，程序无法正常运行，即将退出！"), TEXT("提示"), MB_OK);
		PostQuitMessage(0);
		return; 
	}

	m_hHook = NULL;
 
	//将复选框的按钮以及确定按钮变亮
    m_CBWeChat.EnableWindow(TRUE);
    m_CBYoudaoNote.EnableWindow(TRUE);
    m_pWndOk->EnableWindow(TRUE);

    //将取消按钮变灰
    m_pWndCancle->EnableWindow(FALSE);
}

//收到微信发来的消息
LRESULT CMultiOpenDlg::OnWeChatMessage(WPARAM wParam, LPARAM lParam)
{
	DWORD dwPid = (DWORD)wParam;

	if (m_CBWeChat.GetCheck())
	{
        if (dwPid)
        {
            m_MutualClose.CloseMutualHandle(dwPid, WECHAT);
        }
	}

	return 0;
}

//收到有道云发来的消息
LRESULT CMultiOpenDlg::OnYoudaoMessage(WPARAM wParam, LPARAM lParam)
{
	DWORD dwPid = (DWORD)wParam;

	if (m_CBYoudaoNote.GetCheck())
	{
        if (dwPid)
        {
            m_MutualClose.CloseMutualHandle(dwPid, YOUDAONOTE);
        }
	}

	return 0;
}


LRESULT CMultiOpenDlg::OnShell_NotifyIcon(WPARAM wParam, LPARAM lParam)
{
    switch(lParam)
    {
		case WM_RBUTTONUP:  //鼠标右键弹起
		{
			CMenu menu;
			POINT point;
			HMENU hmenu = NULL;

			//得到鼠标位置   
			GetCursorPos(&point);

			//声明一个弹出式菜单   
			menu.CreatePopupMenu();

			//增加菜单选项，并且指定点击菜单选项时发送的命令
			menu.AppendMenu(MF_STRING, WM_DESTROY, TEXT("退出"));

			SetForegroundWindow();

			//确定弹出式菜单的位置   
			menu.TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, this);

			//资源回收   
			hmenu = menu.Detach();
			menu.DestroyMenu();
			break;
		}
		case WM_LBUTTONUP:  //鼠标左键弹起
		{
			//显示主窗口  
			ShowWindow(SW_SHOWNORMAL);

			//将窗口放到其他进程前面
			SetForegroundWindow();
			break;
		}
    }

    return 0;
}


//当点击右上角 x 按钮时，将窗口放到托盘栏
void CMultiOpenDlg::OnClose()
{
    m_Notify.cbSize = sizeof(NOTIFYICONDATA);
    m_Notify.hWnd = this->m_hWnd;
    m_Notify.uID = IDI_MYICON;
    m_Notify.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    lstrcpy(m_Notify.szTip, TEXT("MultiOpen"));
    m_Notify.uCallbackMessage = WM_SHELL_NOTIFYICON;
    m_Notify.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_MYICON));
    Shell_NotifyIcon(NIM_ADD, &m_Notify);

	//隐藏主窗口
	ShowWindow(SW_HIDE);
}


void CMultiOpenDlg::OnDestroy()
{
	CDialogEx::OnDestroy();

    if (m_hHook == NULL)
    {
        return;
    }

    UnhookWindowsHookEx(m_hHook);
    m_hHook = NULL;

    Shell_NotifyIcon(NIM_DELETE, &m_Notify);
}


HBRUSH CMultiOpenDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

	return hbr;
}
